/**
  ******************************************************************************
  * @file    main.c
  * @author  AE Team
  * @version 1.0.3
  * @date    2024-05-28
  * @brief   本样例演示通过串口1(PA06)以及SmartCard复位引脚(PA03)实现SmartCard的
  *          冷启动、通信速率由8064(3MHz/372)修改为16129(3MHz/372*2)以及APDU通讯
  *          通过串口2(PB02、PA04)实现fputc函数，进而使用Printf函数，实现上位机
  *          实时显示执行过程
  *
  * @note    硬件平台：SYM32L010_StartKit_V1.0
  *          接线说明：断开J12、J22、J23
  *                    短接J13
  *
  *                    DVCC  接 SmartCard 的  VCC
  *                    DVSS  接 SmartCard 的  GND
  *                    PB03  接 SmartCard 的  CLK
  *                    PA03  接 SmartCard 的  RST
  *                    PA06  接 SmartCard 的  IO   并外接上拉电阻(1~3KΩ)
  *
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2024 SIYIMicro.
  * All rights reserved.</center></h2>
  *
  *
  ******************************************************************************
  */


/******************************************************************************/
/* Include files                                                              */
/******************************************************************************/
#include "main.h"
#include "sym32l010_hal_sysctrl.h"
#include "sym32l010_hal_systick.h"
#include "sym32l010_hal_gpio.h"
#include "sym32l010_hal_uart.h"

/******************************************************************************/
/* Local pre-processor symbols/macros ('#define')                             */
/******************************************************************************/
#define   SMARTCARD_RST_SetHigh()    HAL_GPIO_WritePins(SYM_GPIOA, GPIO_PIN_3, GPIO_PIN_SET) // 智能卡复位引脚拉高
#define   SMARTCARD_RST_SetLow()     HAL_GPIO_WritePins(SYM_GPIOA, GPIO_PIN_3, GPIO_PIN_RESET) // 智能卡复位引脚拉低

#define   SC_OK               0x00
#define   SC_NULL             0x01
#define   SC_TIMEOUT          0xC0

/******************************************************************************/
/* Global variable definitions (declared in header file with 'extern')        */
/******************************************************************************/
UART_HandleTypeDef hUartSmartCard;
UART_HandleTypeDef hUartHost;

/******************************************************************************/
/* Local type definitions ('typedef')                                         */
/******************************************************************************/

/******************************************************************************/
/* Local function prototypes ('static')                                       */
/******************************************************************************/
static void UartSmartCard_Init(void);
static void UartHost_Init(void);
uint8_t SmartCard_HotRst(uint8_t *pRxBuf, uint16_t *pRxCnt);          // 智能卡热复位
void    SmartCard_SendBytes(uint8_t *pTxBuf, uint16_t TxCnt);         // 智能卡数据发送函数
uint8_t SmartCard_RecvBytes(uint8_t *pRxBuf, uint16_t *pRxCnt);       // 智能卡数据接收函数
uint8_t SmartCard_RecvOneByteUntillTimeout(uint8_t *pRxBuf, uint16_t TimeOutInMs); // 智能卡等待响应超时
void    SmartCard_APDU(uint8_t *pTxBuf, uint8_t TxCnt, uint8_t *pRxBuf, uint16_t *pRxCnt); // 智能卡APDU收发函数

/******************************************************************************/
/* Local variable definitions ('static')                                      */
/******************************************************************************/

/******************************************************************************/
/* Local pre-processor symbols/macros ('#define')                             */
/******************************************************************************/

/******************************************************************************/
/* Function implementation - global ('extern') and local ('static')           */
/******************************************************************************/


/*******************************************************************************
 ** \brief  Main function of project
 **
 ** \return uint32_t return value, if needed
 **
 **
 ******************************************************************************/
int32_t main(void)
{
    uint8_t  ATR_Buf[50], ReceiveBuf[50], SendBuf[50];
    uint16_t ReceiveCnt;

    // 初始化系统时钟
    HAL_SysCtrl_ConfigWaitCycle(24000000);
    HAL_SysCtrl_HSI_SetDiv(HSIOSC_TO_HSI24MHZ);

    // 初始化SysTick
    HAL_InitTick(24000000);

    // 初始化智能卡UART
    UartSmartCard_Init();

    // 初始化上位机UART
    UartHost_Init();

    while (1)
    {
        //--------------------------------------------------------
        // 切换到 SmartCard 初始波特率 8064 (3MHz/372)
        hUartSmartCard.Init.BaudRate = 8064;                          // 波 特 率:8064 (3MHz/372)
        HAL_UART_Init(&hUartSmartCard);                               // 初始化UART
        HAL_UART_TXD_Enable(hUartSmartCard.Instance);                 // 使能 UART 的TXD功能
        HAL_UART_RXD_Enable(hUartSmartCard.Instance);                 // 使能 UART 的RXD功能
        //--------------------------------------------------------
        // SmartCard 热复位
        HAL_Delay(2000);
        printf("\r\nThe card is hot resetting...\r\n");
        if (SC_OK == SmartCard_HotRst(ATR_Buf, &ReceiveCnt))
        {
            printf("The ATR of the smart card is:");
            for (uint8_t i = 0; i < ReceiveCnt; i++)                  // 把接收到的ATR转化为ASCII码发送到上位机
            {
                printf("%02X ", ATR_Buf[i]);
            }
        }
        else
        {
            printf("The hot reset of the smartcard is failed. Please check and power on the smartcard again!\r\n");
            while (1);
        }
        //--------------------------------------------------------
        // PPS，更改SmartCard的波特率
        SendBuf[0] = 0xFF;
        SendBuf[1] = 0x10;
        SendBuf[2] = 0x12;                                            // F:372   D:2  波特率:16129 (3MHz/372*2)
        SendBuf[3] = SendBuf[0] ^ SendBuf[1] ^ SendBuf[2];
        SmartCard_SendBytes(SendBuf, 4);
        // 接收PPS响应，并通过UART2发送到上位机
        ReceiveCnt = 4;
        SmartCard_RecvBytes(ReceiveBuf, &ReceiveCnt);
        printf("\r\nThe PPS of the smart card is:");
        for (uint8_t i = 0; i < ReceiveCnt; i++)                      // 把接收到的PPS响应数据转化为ASCII码发送到上位机
        {
            printf("%02X ", ReceiveBuf[i]);
        }
        // 更改SmartCard波特率为 16129 (3MHz/372*2)
        if (SendBuf[2] == ReceiveBuf[2])
        {
            hUartSmartCard.Init.BaudRate = 16129;                     // 波 特 率:16129 (3MHz/372*2)
            HAL_UART_Init(&hUartSmartCard);                           // 初始化UART
            HAL_UART_TXD_Enable(hUartSmartCard.Instance);             // 使能 UART 的TXD功能
            HAL_UART_RXD_Enable(hUartSmartCard.Instance);             // 使能 UART 的RXD功能
            printf("\r\nSmart card PPS is succeeded, Baud rate is switched to 16129!\r\n");
        }
        else
        {
            printf("\r\nSmart card PPS is failed!\r\n");
            while (1);
        }

        //--------------------------------------------------------
        // APDU ,进入到3F00文件,并通过UART1发送返回结果
        SendBuf[0] = 0x00;
        SendBuf[1] = 0xA4;
        SendBuf[2] = 0x00;
        SendBuf[3] = 0x00;
        SendBuf[4] = 0x02;
        SendBuf[5] = 0x3f;
        SendBuf[6] = 0x00;
        SmartCard_APDU(SendBuf, 7, ReceiveBuf, &ReceiveCnt);
        printf("The APDU of the smart card:");

        for (uint8_t i = 0; i < ReceiveCnt; i++)                      // 把接收到的APDU响应数据转化为ASCII码发送到上位机
        {
            printf("%02X ", ReceiveBuf[i]);
        }

        // APDU ,获取随机数,并通过UART2发送返回结果
        SendBuf[0] = 0x00;
        SendBuf[1] = 0x84;
        SendBuf[2] = 0x00;
        SendBuf[3] = 0x00;
        SendBuf[4] = 0x08;
        SmartCard_APDU(SendBuf, 5, ReceiveBuf, &ReceiveCnt);
        printf("\r\nThe APDU of the smart card:");
        for (uint8_t i = 0; i < ReceiveCnt; i++)                      // 把接收到的APDU响应数据转化为ASCII码发送到上位机
        {
            printf("%02X ", ReceiveBuf[i]);
        }
    }
}


/*******************************************************************************
 * @brief  上位机(UART 2)初始化
 * @param  None
 * @retval None
 *
 */
static void UartHost_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;

    // 使能外设时钟
    HAL_SYSCTRL_UART2_CLK_ENABLE();

    UART_HandleTypeDef hUart;

    MemClr(&GPIO_InitStruct, sizeof(GPIO_InitStruct));
    MemClr(&hUart, sizeof(hUart));

    // Config PB02 AS UART2.TXD
    GPIO_InitStruct.Pins = GPIO_PIN_2;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;                       // PB02推挽输出
    HAL_GPIO_Init(SYM_GPIOB, &GPIO_InitStruct);
    AFx_UART2TXD_PB02();

    // Config PA04 AS UART2.RXD
    GPIO_InitStruct.Pins = GPIO_PIN_4;
    GPIO_InitStruct.Pull = GPIO_PULL_UP;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    HAL_GPIO_Init(SYM_GPIOA, &GPIO_InitStruct);
    AFx_UART2RXD_PA04();

    // 配置上位机
    hUart.Instance = SYM_UART2;
    //hUart.Init.WorkMode    = UART_WORKMODE_ASYN;                    // 异步串口
    hUart.Init.SingleWireEn  = UART_SINGLEWIRE_DISABLE;               // 采用双线制 通信
    //hUart.Init.TxRxPolarity = UART_RXTXPOLARITY_POSITIVE;           // TXD RXD 不反向
    //hUart.Init.HwFlowCtrl  = UART_HWFLOWCTRL_NONE;                  // 没有流控
    //hUart.Init.RxdStart    = UART_RXDSTART_EDGE;                    // 下降沿作为起始位
    //hUart.Init.ClockSource = UART_CLKSRC_PCLK;                      // 时 钟 源:PCLK
    hUart.Init.PclkFreq      = 24000000;                              // PCLK频率:24MHz
    hUart.Init.BaudRate      = 9600;                                  // 波 特 率:9600
    hUart.Init.ParityMode    = UART_PARITYMODE_NONE;                  // 无校验位
    hUart.Init.StopBits      = UART_STOPBITS_1;                       // STOP = 1

    HAL_UART_Init(&hUart);                                            // 初始化UART2
    HAL_UART_TXD_Enable(hUart.Instance);                              // 使能 UART2 的TXD功能
}


/*******************************************************************************
 * @brief  智能卡(UART 1)初始化
 * @param  None
 * @retval None
 *
 */
static void UartSmartCard_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;

    // 使能外设时钟
    HAL_SYSCTRL_GPIOA_CLK_ENABLE();
    HAL_SYSCTRL_GPIOB_CLK_ENABLE();
    HAL_SYSCTRL_UART1_CLK_ENABLE();

    // Config PB03 AS SmartCard_CLK 3MHz (24MHz / 8)
    HAL_SysCtrl_ClkOut_MCO_PB03(SYSCTRL_MCO_SRC_PCLK, SYSCTRL_MCO_DIV8);

    MemClr(&GPIO_InitStruct, sizeof(GPIO_InitStruct));

    // Config PA03 AS SmartCard_Reset
    GPIO_InitStruct.Pins = GPIO_PIN_3;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;                       // 推挽输出
    HAL_GPIO_Init(SYM_GPIOA, &GPIO_InitStruct);

    // Config PA06 AS UART1.TXD (SmartCard_IO)
    AFx_UART1TXD_PA06();
    GPIO_InitStruct.Pins = GPIO_PIN_6;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;                       // 开漏输出  并 外接上拉电阻(1~3KΩ)
    HAL_GPIO_Init(SYM_GPIOA, &GPIO_InitStruct);

    // Config SmartCard UART1
    hUartSmartCard.Instance = SYM_UART1;
    //hUart.Init.WorkMode    = UART_WORKMODE_ASYN;                    // 异步串口
    hUartSmartCard.Init.SingleWireEn  = UART_SINGLEWIRE_ENABLE;       // 采用单总线 通信
    //hUart.Init.TxRxPolarity = UART_RXTXPOLARITY_POSITIVE;           // TXD RXD 不反向
    //hUart.Init.HwFlowCtrl  = UART_HWFLOWCTRL_NONE;                  // 没有流控
    //hUart.Init.RxdStart    = UART_RXDSTART_EDGE;                    // 下降沿作为起始位
    hUartSmartCard.Init.ClockSource   = UART_CLKSRC_PCLK;             // 时 钟 源:PCLK
    hUartSmartCard.Init.PclkFreq      = 24000000;                     // PCLK频率:24MHz
    hUartSmartCard.Init.BaudRate      = 8064;                         // 波 特 率:8064 (3MHz/372)
    hUartSmartCard.Init.ParityMode    = UART_PARITYMODE_EVEN;         // 偶校验
    hUartSmartCard.Init.StopBits      = UART_STOPBITS_1;              // STOP = 1

    HAL_UART_Init(&hUartSmartCard);                                   // 初始化UART
    HAL_UART_TXD_Enable(hUartSmartCard.Instance);                     // 使能 UART 的TXD功能
    HAL_UART_RXD_Enable(hUartSmartCard.Instance);                     // 使能 UART 的RXD功能
}


/*******************************************************************************
 * @brief  SmartCard_HotRst 智能卡热复位
 * @param  pRxBuf : 接收到的数据
 * @param  pRxCnt : 接收数据的长度
 * @retval SC_OK  : 接收到正确数据
 *         SC_NULL: 接收到空数据
 *
 */
uint8_t SmartCard_HotRst(uint8_t *pRxBuf, uint16_t *pRxCnt)
{
    SMARTCARD_RST_SetLow();                                           // 拉低智能卡复位引脚
    HAL_Delay(1);
    SMARTCARD_RST_SetHigh();                                          // 拉高智能卡复位引脚

    *pRxCnt = 50;
    SmartCard_RecvBytes(pRxBuf, pRxCnt);                              // 接收ATR数据包

    if (*pRxCnt == 0x00)
    {
        return SC_NULL;
    }
    else
    {
        return  SC_OK;
    }
}


/*******************************************************************************
 * @brief  SmartCard_SendBytes 智能卡数据发送函数
 * @param  pTxBuf: 所发送的数据
 * @param  TxCnt : 发送数据的长度
 * @retval None
 *
 */
void SmartCard_SendBytes(uint8_t *pTxBuf, uint16_t TxCnt)
{
    HAL_UART_Transmit(&hUartSmartCard, pTxBuf, TxCnt, 0);
}


/*******************************************************************************
 * @brief  SmartCard_RecvOneByteUntillTimeout 智能卡等待超时函数
 * @param  TimeOutInMs: 设置超时时间(单位:ms)
 * @param  pRxBuf     : 返回接收到的字节
 * @retval SC_OK      : 接收到正确数据
 *         SC_TIMEOUT : 接收超时
 *
 */
uint8_t SmartCard_RecvOneByteUntillTimeout(uint8_t *pRxBuf, uint16_t TimeOutInMs)
{
    uint32_t MaxTick = HAL_GetTick() + TimeOutInMs;

    while (HAL_GetTick() < MaxTick)
    {
        if (HAL_UART_GET_FLAG(&hUartSmartCard, UART_IT_FLAG_RC))
        {
            *pRxBuf = HAL_UART_RecvByte(hUartSmartCard.Instance);
            return(SC_OK);
        }
    }

    return(SC_TIMEOUT);
}


/*******************************************************************************
 * @brief  SmartCard_RecvBytes 智能卡接收函数
 * @param  pRxBuf     : 接收到的数据
 * @param  pRxCnt     : 接收数据的长度
 * @retval SC_OK      : 接收到正确数据
 *         SC_TIMEOUT : 接收超时
 *
 */
uint8_t SmartCard_RecvBytes(uint8_t *pRxBuf, uint16_t *pRxCnt)
{
    uint8_t  tmp8;
    uint16_t RxTimeOut = 200;
    uint16_t RxCnt_Obj, RxCnt_Cur;

    RxCnt_Cur = 0x00;
    RxCnt_Obj = *pRxCnt;

    while (RxCnt_Cur < RxCnt_Obj)
    {
        tmp8 = SmartCard_RecvOneByteUntillTimeout(pRxBuf, RxTimeOut);
        if (SC_OK == tmp8)
        {
            RxCnt_Cur++;
            pRxBuf++;
        }
        else
        {
            break;
        }

        RxTimeOut = 10;
    }

    *pRxCnt = RxCnt_Cur;

    if (RxCnt_Cur == RxCnt_Obj)
    {
        return(SC_OK);
    }
    else
    {
        return(SC_TIMEOUT);
    }

}


/*******************************************************************************
 * @brief  SmartCard_APDU 智能卡APDU收发函数
 * @param  pTxBuf: 所需发送的数据
 * @param  TxCnt : 发送数据的长度
 * @param  pRxBuf: 接 收 到的数据
 * @param  pRxCnt: 接收数据的长度
 * @retval None
 *
 */
void SmartCard_APDU(uint8_t *pTxBuf, uint8_t TxCnt, uint8_t *pRxBuf, uint16_t *pRxCnt)
{
    uint8_t status;
    uint8_t AckIns;

    SmartCard_SendBytes(pTxBuf, 5);

    do                                                                // 处理60 (WTX)
    {
        *pRxCnt = 1;
        status = SmartCard_RecvBytes(&AckIns, pRxCnt);
    }
    while ((status == SC_OK) && (AckIns == 0x60));

    if (status == SC_OK)
    {
        if (AckIns == pTxBuf[1])                                      // 卡片返回ins
        {
            if (TxCnt > 5)                                            // 发送剩余的数据
            {
                SmartCard_SendBytes(pTxBuf + 5, TxCnt - 5);           // send DATA BODY

                do                                                    // 处理60 (WTX)
                {
                    *pRxCnt = 1;
                    status = SmartCard_RecvBytes(&AckIns, pRxCnt);

                }
                while ((status == SC_OK) && (AckIns == 0x60));

                if (status == SC_OK)                                  // 接收SW2
                {
                    pRxBuf[0] = AckIns;

                    *pRxCnt = 0x01;
                    status = SmartCard_RecvBytes(pRxBuf + 1, pRxCnt);
                    if (status == SC_OK)
                    {
                        *pRxCnt = 2;
                    }
                }

            }
            else                                                      // 接收LE个数据+SW
            {
                *pRxCnt = pTxBuf[4] + 2;
                status = SmartCard_RecvBytes(pRxBuf, pRxCnt);
            }
        }
        else                                                          // 卡片已返回SW1，接收SW2
        {
            pRxBuf[0] = AckIns;

            *pRxCnt = 0x01;
            status = SmartCard_RecvBytes(pRxBuf + 1, pRxCnt);
            if (status == SC_OK)
            {
                *pRxCnt = 2;
            }
        }
    }
}


/*******************************************************************************
 ** EOF (not truncated)
 ******************************************************************************/
#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
    /* USER CODE BEGIN */
    /* User can add his own implementation to report the file name and line number,
       tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
    /* USER CODE END */
}
#endif /* USE_FULL_ASSERT */


/************************ (C) COPYRIGHT SIYIMicro *****END OF FILE*************/
